package com.cloudgateway.rule;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.ribbon.ExtendBalancer;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.cloudgateway.config.AuthFilterConfig;
import com.cloudgateway.config.ReactiveRequestContextHolder;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Tag rule
 *
 * @description: nacos标签路由功能
 *   cloud:
 *     nacos:
 *       server-addr: nacos-server.common-middleware.svc.cluster.bberp
 *       discovery:
 *         metadata:
 *           route: cyj
 * @author: cyj
 * @date 2022 -05-27 15:11:20
 *
 *
 */
@Component
@Slf4j
public class NacosTagRule extends AbstractLoadBalancerRule {

    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Autowired
    private NacosServiceManager nacosServiceManager;

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

    @SneakyThrows
    @Override
    public Server choose(Object o) {

        String routeHead = "route";
        List<String> heads = AuthFilterConfig.requestThreadLocal.get().getHeaders().get(routeHead);
        String routeTag = CollectionUtils.isEmpty(heads) ? null : heads.get(0);
        AuthFilterConfig.requestThreadLocal.remove();


        String clusterName = this.nacosDiscoveryProperties.getClusterName();
        String group = this.nacosDiscoveryProperties.getGroup();
        DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
        String name = loadBalancer.getName();

        NamingService namingService = nacosServiceManager
                .getNamingService(nacosDiscoveryProperties.getNacosProperties());
        List<Instance> instances = namingService.selectInstances(name, group, true, true);
        if (CollectionUtils.isEmpty(instances)) {
            log.warn("no instance in service {}", name);
            return null;
        }
        List<Instance> instancesToChoose = instances;
        if (StringUtils.isNotBlank(clusterName)) {
            List<Instance> sameClusterInstances = instances.stream()
                    .filter(instance -> Objects.equals(clusterName,
                            instance.getClusterName()))
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(sameClusterInstances)) {
                instancesToChoose = sameClusterInstances;
            }
        }
        //筛选带标签的实例
        List<Instance> tagInstance = instancesToChoose.stream()
                .filter(instance -> instance.getMetadata().get(routeHead) != null)
                .collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(tagInstance) && StringUtils.isNotBlank(routeTag)) {
            //筛选和请求流量相同的标签实例
            List<Instance> candidateTagInstance = tagInstance.stream()
                    .filter(instance -> instance.getMetadata().get(routeHead).equals(routeTag))
                    .collect(Collectors.toList());
            //标签路由
            if (!CollectionUtils.isEmpty(candidateTagInstance)) {
                Instance instance = ExtendBalancer.getHostByRandomWeight2(candidateTagInstance);
                return new NacosServer(instance);
            }
        }
        // 带标签路由的实例不执行
        if (!CollectionUtils.isEmpty(tagInstance)) {
            instancesToChoose.removeAll(tagInstance);
        }
        if (CollectionUtils.isEmpty(instancesToChoose)) {
            log.warn("no instance in service {}", name);
            return null;
        }
        //正常路由
        Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToChoose);
        return new NacosServer(instance);
    }
}
